#include "config.h"
#include "methodDef.h"
#include "methodCollection_t.h"
#include "cbgl.h"
#include "cmdBuffer_t.h"
#include "export.h"


methodCollection_t* g_gl = 0;
int g_state = CBGL_IMMEDIATE;
cmdBuffer_t* g_cB = 0;
int g_state_export = CBGL_EXPORT_OFF;
int g_exportInit = 0;
int g_useDoubleBuffer = CBGL_USE_SINGLE_BUFFER;
cmdBuffer_t* g_doubleCB = 0;
CRITICAL_SECTION g_mutex;

__declspec(dllexport) void cbglInitialize()
{
	g_cB = cmdBuffer_create();
	g_gl = loadMethodCollection();	
	g_state = CBGL_IMMEDIATE;
	g_state_export = CBGL_EXPORT_OFF;
	g_useDoubleBuffer = CBGL_USE_SINGLE_BUFFER;
	InitializeCriticalSection(&g_mutex);
}

__declspec(dllexport) void cbglDestroy()
{
	if(g_doubleCB)
	{
		cmdBuffer_destroy(g_doubleCB);
		g_doubleCB = 0;
	}

	cmdBuffer_destroy(g_cB);
	unloadMethodCollection(g_gl);
	export_close();
	DeleteCriticalSection(&g_mutex);
}

__declspec(dllexport) void cbglExecute()
{
	cmdBuffer_t* swap;

	if(g_useDoubleBuffer == CBGL_USE_SINGLE_BUFFER)
	{
		if(g_state_export == CBGL_EXPORT_ON)
			export_cb(g_cB);

		cmdBuffer_execute(g_cB);
	}
	else //use double buffering
	{
		EnterCriticalSection(&g_mutex);
		
		// flip buffers
		swap = g_cB;
		g_cB = g_doubleCB;
		g_doubleCB = swap;
		
		LeaveCriticalSection(&g_mutex);
		
		// execute buffer
		if(g_state_export == CBGL_EXPORT_ON)
			export_cb(g_doubleCB);

		cmdBuffer_execute(g_doubleCB);
	}
}

__declspec(dllexport) cbglChangeMode(int mode)
{
	if((mode == CBGL_IMMEDIATE) || (mode == CBGL_DEFFERED))
	{
		if((mode == CBGL_IMMEDIATE) && (g_state == CBGL_DEFFERED))
		{
			cbglExecute();
		}

		g_state = mode;
	}
	else if((mode == CBGL_EXPORT_ON) || (mode == CBGL_EXPORT_OFF))
	{

		if((!g_exportInit) && (mode == CBGL_EXPORT_ON))
		{
			export_init("export.xml", g_gl);
			g_exportInit = 1;
		}
		
		g_state_export = mode;
	}
	else if((mode == CBGL_USE_DOUBLE_BUFFER) || (mode == CBGL_USE_SINGLE_BUFFER))
	{
		if(mode != g_useDoubleBuffer)
		{
			if(mode == CBGL_USE_DOUBLE_BUFFER)
			{
				// create another command buffer
				g_doubleCB = cmdBuffer_create();
			}
			else//single buffer
			{
				// remove double buffer
				EnterCriticalSection(&g_mutex);

				cmdBuffer_destroy(g_doubleCB);
				g_doubleCB = 0;

				LeaveCriticalSection(&g_mutex);
			}

			g_useDoubleBuffer = mode;
		}
	}
}